#include "aio_thread.h"
#include "../global/head.h"
#include "../xos/head.h"
#include "../buf/head.h"
#include "aio_impl.h"
#include "aio_helper.h"

/////////////////////////////////////////////////////////////////////////////////////////
// 
namespace xos
{
    aio_thread::aio_thread( aio_impl * pAioImpl ) : m_pAioImpl( pAioImpl )
    {
        m_pThread = 0;
    }

    aio_thread::~aio_thread()
    {
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 

    int aio_thread::notify( msg_impl * p )
    {
        int nRet = 0;
        return nRet;
    }

    int aio_thread::init()
    {
        int nRet = 0;

        if( 0 == nRet )
        {
            nRet = g_pXosImpl->create( i_xos::XOS_OBJ_THREAD, ( void ** )&m_pThread );
        }

        if( 0 == nRet )
        {
            m_pThread->create( aio_thread::thread, this );
        }

        return nRet;
    }

    int aio_thread::term()
    {
        int nRet = 0;

        if( m_pThread )
        {
            m_pThread->wait();
            m_pThread->release();
            m_pThread = 0;
        }

        m_pAioImpl = 0;

        return nRet;
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 

    void * aio_thread::thread( void * lpData )
    {
        aio_thread & obj = *( aio_thread * )lpData;
        int nRet = 0;

        while( 0 == nRet )
        {
            nRet = obj.run();
        }

        return 0;
    }

    int aio_thread::run()
    {
        using namespace std;

        int nRet = 0;

        OverlappedEx * lpOverlappedEx = 0;
        aio_key * lpAioKey = 0;
        aio_data * lpAioData = 0;
        DWORD dwBytes = 0;
        DWORD dwErr = 0;
        BOOL bRet = TRUE;

        if( 0 == nRet )
        {
            bRet = GetQueuedCompletionStatus( m_pAioImpl->m_hIocp, &dwBytes, ( ULONG_PTR * )&lpAioKey, ( LPOVERLAPPED * )&lpOverlappedEx, INFINITE );
        }

        if( ( 0 == nRet ) && !bRet )
        {
            dwErr = GetLastError();

            cout << "GetQueuedCompletionStatus failed = " << dwErr << endl;
            cout << "                  lpOverlappedEx = " << lpOverlappedEx << endl;
            cout << "                        lpAioKey = " << lpAioKey << endl;
            cout << "                         dwBytes = " << dwBytes << endl;

            switch( dwErr )
            {
            case ERROR_ABANDONED_WAIT_0:
                {
                    nRet = 1;
                }
                break;
            default:
                {
                    if( !lpOverlappedEx )
                    {
                        nRet = 2;
                    }
                }
                break;
            }
        }

        if( ( 0 == nRet ) && lpOverlappedEx )
        {
            lpAioData = lpOverlappedEx->m_pAioData;
        }

        if( ( 0 == nRet ) && !bRet && lpAioData )
        {
            lpAioData->m_dwErrCode = dwErr;
        }

        if( 0 == nRet )
        {
            aio_helper tool( m_pAioImpl );
            bool quit = tool.proc( bRet ? 0 : 1, dwBytes, lpAioKey, lpAioData );
            if( quit )
            {
                nRet = 1;
            }
        }

        if( 2 == nRet )
        {
            nRet = 0;
        }

        return nRet;
    }

} // xos
